package com.physics.mps.module.compute;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.physics.mps.common.config.constant.Constants;
import com.physics.mps.common.config.properties.ApiProperties;
import com.physics.mps.common.exception.BusinessException;
import com.physics.mps.common.util.AssertUtil;
import com.physics.mps.common.util.LoginUtil;
import com.physics.mps.common.util.MinioUtil;
import com.physics.mps.common.util.OkHttpUtil;
import com.physics.mps.entity.dto.SubTaskEntity;
import com.physics.mps.entity.dto.TaskComputeResultEntity;
import com.physics.mps.entity.enums.CodeEnum;
import com.physics.mps.entity.enums.ScriptStatusEnum;
import com.physics.mps.entity.vo.*;
import com.physics.mps.entity.vo.*;
import com.physics.mps.entity.vo.api.Result;
import com.physics.mps.entity.vo.api.UploadVo;
import com.physics.mps.mapper.AppModuleMapper;
import com.physics.mps.module.abaqus.AbaqusComputeService;
import com.physics.mps.module.abaqus.AbstractAbaqusComputeHandler;
import com.physics.mps.module.checker.AbaqusComputeChecker;
import com.physics.mps.module.checker.AnsysComputeChecker;
import com.physics.mps.module.checker.ComputeChecker;
import com.physics.mps.module.checker.ComsolComputeChecker;
import com.physics.mps.module.task.sub.SubTaskService;
import com.physics.mps.module.util.JsonResolver;
import com.physics.mps.module.util.PyUtils;
import com.physics.mps.module.util.TaskMonitor;
import com.physics.mps.entity.vo.result.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Response;
import okhttp3.ResponseBody;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

/**
 * @author mcsoft
 * @since 2023/9/12
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ComputeServiceImpl extends AbaqusComputeService {

    /**
     * app模块查询接口
     */
    private final AppModuleMapper appModuleMapper;

    /**
     * 计算结果数据库接口
     */
    private final TaskComputeResultService taskComputeResultService;

    /**
     * 任务数据库接口
     */
    private final SubTaskService subTaskService;

    /**
     * 服务器abaqus安装路径
     */
    @Value("${simulate.abaqus.install-path}")
    private String installPath;

    /**
     * abaqus结果输出路径
     */
    @Value("${simulate.abaqus.output-path}")
    private String outputPath;

    /**
     * abaqus cae数据保存路径
     */
    @Value("${simulate.abaqus.cae-path}")
    private String caePath;

    /**
     * abaqus 脚本保存路径
     */
    @Value("${simulate.abaqus.script-path}")
    private String scriptPath;

    /**
     * 参数路径
     */
    private final JsonResolver js;

    private final ExecutorService readScriptExecutorService;

    private final ExecutorService executeScriptExecutorService;

    /**
     * 计算结果上传接口
     */
    private final ApiProperties apiProperties;

    /**
     * 文件存储接口
     */
    private final MinioUtil minioUtil;


    /**
     * 提交计算abaqus任务
     * @param startComputeVo 任务参数
     * @return 计算成功或失败，失败则返回报错信息
     * @throws Exception
     */
    public ResponseResult compute(StartComputeVo startComputeVo) throws Exception {
//        String content = readFileContent(file);
        log.info("=== abaqus 仿真主程序发送参数{} ===", JSONUtil.toJsonStr(startComputeVo));
        Map<String, Object> treeMap = new TreeMap<>(startComputeVo.getParam());
        //根据模块id调用对应的解析器 解析参数 封装为参数对象
        AbaqusComputeParam abaqusParam = parseJsonToParam(startComputeVo.getAppModuleId(), JSONUtil.toJsonStr(treeMap));
        log.info(abaqusParam.toString());
        AssertUtil.isBlank(startComputeVo.getTaskName(), CodeEnum.TASK_NAME_NOT_NULL);
        ComputeChecker checker = configChecker(startComputeVo);
        checker.check();
        abaqusParam.getJobVo().setJobName(startComputeVo.getTaskName() + "-" + IdUtil.simpleUUID());
        //根据模块id调用对对应的处理器 生成脚本字符串
        String s = executeHandler(startComputeVo.getAppModuleId(), abaqusParam);
        //执行内容写入脚本文件
        List<String> list = writeToPy(abaqusParam.getJobVo().getJobName(), s);
        //脚本文件提交执行
        return executeCommand(list, abaqusParam, startComputeVo);
    }

    /**
     * 根据不同的appid选择不同的checker
     * @param startComputeVo
     * @return
     */
    private ComputeChecker configChecker(StartComputeVo startComputeVo) {
        String appId = startComputeVo.getAppId();
        ComputeChecker checker;
        switch (appId) {
            case "1":
                SimulatePathVo simulatePathVo = new SimulatePathVo();
                simulatePathVo.setInstallPath(installPath);
                simulatePathVo.setOutputPath(outputPath);
                simulatePathVo.setScriptPath(scriptPath);
                simulatePathVo.setCaePath(caePath);
                checker = new AbaqusComputeChecker();
                checker.setSimulatePathVo(simulatePathVo);
                break;
            case "2":
                checker = new ComsolComputeChecker();
                break;
            case "3":
                checker = new AnsysComputeChecker();
                break;
            default:
                throw new BusinessException(CodeEnum.APP_ID_NOT_EXIST);
        }
        return checker;
    }

    /**
     * 执行计算命令
     * @param list 脚本存放地址
     * @param abaqusParam 计算所需参数
     * @param startComputeVo 任务参数
     * @return
     */
    private ResponseResult executeCommand(List<String> list, AbaqusComputeParam abaqusParam, StartComputeVo startComputeVo) {
        //执行计算的命令
        String builder = " cd " +
                list.get(0) +
                " && " +
                " abaqus cae noGUI=" +
                list.get(1);
        ProcessBuilder processBuilder = new ProcessBuilder("cmd.exe", "/c", builder);

        String token = LoginUtil.getToken();

        // 子任务未提前创建则先创建，否则关联已创建的子任务
        SubTaskEntity subTaskEntity;

        if (StringUtils.isEmpty(startComputeVo.getSubTaskId())) {
            // 创建子任务
            SubTaskEntity subTask = new SubTaskEntity();
            subTask.setName(startComputeVo.getTaskName() + "-" + IdUtil.simpleUUID());
            subTask.setStatus(ScriptStatusEnum.INIT.getStatus());
            subTask.setUserId(Objects.requireNonNull(LoginUtil.getUserId()).toString());
            subTask.setTaskId(IdUtil.fastSimpleUUID());
            subTask.setAppId(startComputeVo.getAppId());
            subTask.setModuleId(startComputeVo.getAppModuleId());
            subTaskService.save(subTask);

            subTaskEntity = subTask;
        } else {
            subTaskEntity = subTaskService.getBaseMapper().selectById(startComputeVo.getSubTaskId());
        }
        AssertUtil.isNull(subTaskEntity, CodeEnum.SUBTASK_NOT_NULL);


        StringBuilder logContent = new StringBuilder();

        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                LoginUtil.setToken(token);
                processBuilder.redirectErrorStream(true);

                // 启动进程
                Process process = processBuilder.start();

                Future<?> outputFuture = getOutPutFuture(logContent, process);

                checkInpCreate(abaqusParam, subTaskEntity, process);


                process.waitFor();
                // Wait for the outputFuture to complete
                outputFuture.get();

                //判断是否成功并进行后续操作
                determinedSuccess(abaqusParam, subTaskEntity, logContent, startComputeVo);

                //读取结果文件，封装为AbaqusResultVo
//                AbaqusResultVo resultVo = generateAbaqusResultVo(abaqusParam, startComputeVo);
            } catch (InterruptedException e) {
                log.error(e.getMessage());
                // 恢复中断状态
                Thread.currentThread().interrupt();
                // 更新任务表状态为“异常”
                subTaskEntity.setStatus(ScriptStatusEnum.EXCEPTION.getStatus());
                subTaskService.saveOrUpdate(subTaskEntity);
            } catch (Exception e) {
                // 更新任务表状态为“异常”
                log.error(e.getMessage());
                subTaskEntity.setStatus(ScriptStatusEnum.EXCEPTION.getStatus());
                subTaskService.saveOrUpdate(subTaskEntity);
            } finally {
                supplyLog(abaqusParam.getJobVo().getJobName(), logContent);
                subTaskEntity.setCmdLog(logContent.toString());
                subTaskService.saveOrUpdate(subTaskEntity);
                LoginUtil.removeAll();
            }
        }, executeScriptExecutorService);

        return ResponseResult.success();
    }

    /**
     * 上传文件
     * @param path 文件路径
     * @return
     */
    private String upload2FileSystem(String path) {
        String filename = Paths.get(path).getFileName().toString();
        ResponseEntity<String> upload = minioUtil.upload(filename, apiProperties.getModuleName(), path);
        if (upload.getStatusCode() != HttpStatus.OK) {
            throw new BusinessException(CodeEnum.TASK_JSON_UPLOAD_FAILED);
        }
        return upload.getBody();
    }

    /**
     * 判断计算是否成功
     * @param abaqusParam 计算参数
     * @param subTaskEntity 当前任务
     * @param logContent 计算日志
     * @param startComputeVo 任务参数
     */
    private void determinedSuccess(AbaqusComputeParam abaqusParam, SubTaskEntity subTaskEntity, StringBuilder logContent, StartComputeVo startComputeVo) {
        // set cmd日志
        subTaskEntity.setCmdLog(logContent.toString());
        // set log日志位置
        String logPath = outputPath + "\\\\" + abaqusParam.getJobVo().getJobName() + ".log";
        // 1.判断log文件是否生成，未生成抛出错误
        if (!FileUtil.exist(logPath)) {
            throw new BusinessException(CodeEnum.STP_FILE_OR_PARAM_ERROR);
        }
        subTaskEntity.setLogPath(logPath);

        // keypoint 如果cmd日志包含error,结果生成失败
        if (logContent.toString().toLowerCase().contains(Constants.ERROR)) {
            throw new BusinessException(CodeEnum.FAILED_TO_GENERATE_RESULTS);
        }

        // 2.根据log日志判断是否仿真成功
        String lastLine = TaskMonitor.readLastLine(logPath);
        String template = "Abaqus JOB %s COMPLETED";
        String jobName = abaqusParam.getJobVo().getJobName();
        String result = String.format(template, jobName);
        if (!lastLine.equals(result)) {
            throw new BusinessException(CodeEnum.FAILED_TO_GENERATE_RESULTS);
        }

        // 上传结果文件(新增)
        String resultFilePath = outputPath + "\\\\" + abaqusParam.getJobVo().getJobName() + ".odb";
        ResponseEntity<String> upload = minioUtil.upload(abaqusParam.getJobVo().getJobName() + ".odb", apiProperties.getModuleName(), resultFilePath);
        if (upload.getStatusCode() != HttpStatus.OK) {
            throw new BusinessException(CodeEnum.TASK_FILE_UPLOAD_FAILED);
        }
//        String url = uploadResultFile(resultFilePath);
        String url = upload.getBody();
        subTaskEntity.setStatus(ScriptStatusEnum.COMPLETE.getStatus());

        TaskComputeResultEntity taskComputeResultEntity = new TaskComputeResultEntity();
        taskComputeResultEntity.setFilePath(outputPath + "\\\\" + abaqusParam.getJobVo().getJobName() + ".odb");
        taskComputeResultEntity.setPicPath(outputPath + "\\\\PNG\\\\" + abaqusParam.getJobVo().getJobName() + ".png");

        // 上传pic图片到minio
        String picFilePath = outputPath + "\\\\PNG\\\\" + abaqusParam.getJobVo().getJobName() + ".png";
        ResponseEntity<String> uploadPic = minioUtil.upload(abaqusParam.getJobVo().getJobName() + ".png", apiProperties.getModuleName(), picFilePath);
        if (uploadPic.getStatusCode() != HttpStatus.OK) {
            throw new BusinessException(CodeEnum.TASK_PIC_UPLOAD_FAILED);
        }
        String body = uploadPic.getBody();

        //读取结果文件，封装为AbaqusResultVo
        AbaqusResultVo resultVo = generateAbaqusResultVo(abaqusParam, startComputeVo);

        String targetPath = outputPath + "\\\\" + abaqusParam.getJobVo().getJobName() + ".json";
        try (OutputStream outputStream = Files.newOutputStream(Paths.get(targetPath))) {
            outputStream.write(JSONUtil.toJsonStr(resultVo).getBytes());
            outputStream.flush();
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new RuntimeException(e);
        }
        String jsonUrl = upload2FileSystem(targetPath);

        //将odb转换为vtu的指令写入数据库，便于后续转换
        StringBuilder vtu = new StringBuilder();
        writeVtu(vtu, abaqusParam, startComputeVo);

        //保存计算结果数据到数据库
        taskComputeResultEntity.setResultUrl(url);
        taskComputeResultEntity.setPicUrl(body);
        taskComputeResultEntity.setJsonUrl(jsonUrl);
        taskComputeResultEntity.setVtu(vtu.toString());
        taskComputeResultService.save(taskComputeResultEntity);

        subTaskEntity.setComputeResultId(taskComputeResultEntity.getId());

        subTaskService.updateById(subTaskEntity);
    }

    /**
     * 检查input文件是否生成
     * @param abaqusParam 计算参数
     * @param subTaskEntity 当前任务
     * @param process 当前计算进程
     */
    private void checkInpCreate(AbaqusComputeParam abaqusParam, SubTaskEntity subTaskEntity, Process process) {
        while (process.isAlive()) {
            // Check for the .inp file generation abaqus生成了inp文件才是running状态
            String inpFilePath = outputPath + "\\\\" + abaqusParam.getJobVo().getJobName() + ".inp";

            if (FileUtil.exist(inpFilePath)) {
                log.info(".inp file has been generated!");

                subTaskEntity.setStatus(ScriptStatusEnum.RUNNING.getStatus());
                // 修改任务状态
                subTaskService.updateById(subTaskEntity);
                break;
            }
        }
    }

    /**
     * 获取当前计算日志
     * @param logContent 计算日志
     * @param process 当前进程
     * @return
     */
    private Future<?> getOutPutFuture(StringBuilder logContent, Process process) {
        // 读取cmd日志信息
        return readScriptExecutorService.submit(() -> {
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK"))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    log.info(line);
                    logContent.append(line).append(System.lineSeparator());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 将计算语句写入脚本
     * @param fileName 脚本文件名
     * @param content 脚本内容
     * @return
     */
    public List<String> writeToPy(String fileName, String content) {
        String fileExtension = ".py";
        String filePath = scriptPath + fileName + fileExtension;
        log.info("=====脚本文件生成路径 {}=====", filePath);
        try {
            Files.write(Paths.get(filePath), content.getBytes());
        } catch (IOException e) {
            throw new BusinessException(CodeEnum.FILE_WRITE_FAILED);
        }
        List<String> strings = new ArrayList<>();
        strings.add(scriptPath);
        strings.add(fileName + fileExtension);
        return strings;
    }

    /**
     * 读取文件内容
     * @param file
     * @return
     * @throws BusinessException
     */
    private String readFileContent(MultipartFile file) throws BusinessException {
        if (file.isEmpty()) {
            throw new BusinessException(CodeEnum.FILE_IS_NULL);
        }

        StringBuilder contentBuilder = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(file.getInputStream(), StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                contentBuilder.append(line).append("\n");
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(CodeEnum.FILE_READ_FAILED);
        }
        return contentBuilder.toString();
    }

    /**
     * 将json封装为计算参数对象
     * @param appModuleId
     * @param content
     * @return
     * @throws BusinessException
     */
    private AbaqusComputeParam parseJsonToParam(String appModuleId, String content) throws BusinessException {
        //根据模块id获取参数解析器的方法
        String methodName = getMethodNameFromDb(appModuleId);
        try {
            //反射调用对应的方法将json封装为计算参数对象
            Method method = js.getClass().getMethod(methodName, String.class, Integer.class);
            return (AbaqusComputeParam) method.invoke(js, content, 1);
        } catch (InvocationTargetException e) {
            Throwable cause = e.getTargetException();
            if (cause instanceof BusinessException) {
                throw (BusinessException) cause;
            }
            log.error(cause.getMessage(), cause);
            throw new BusinessException(CodeEnum.METHOD_INVOCATION_FAILED);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * 获取脚本内容
     * @param appModuleId app模块id
     * @param abaqusParam 计算参数
     * @return
     * @throws BusinessException
     */
    private String executeHandler(String appModuleId, AbaqusComputeParam abaqusParam) throws BusinessException {
        try {
            //根据app模块id获取对应处理器
            String handlerClassName = getHandlerClassNameFromDb(appModuleId);
            AbstractAbaqusComputeHandler handler = (AbstractAbaqusComputeHandler) Class.forName(handlerClassName).getDeclaredConstructor().newInstance();
            //设置处理器参数
            handler.setCaePath(caePath + abaqusParam.getJobVo().getJobName());
            handler.setStpPath(abaqusParam.getStpPath());
            handler.setWorkDir(outputPath);
            handler.setAbaqusComputeParam(abaqusParam);
            //处理器创建计算脚本内容
            String command = handler.createCommand();
            log.info(command);
            return command;
        } catch (InvocationTargetException e) {
            Throwable cause = e.getTargetException();
            if (cause instanceof BusinessException) {
                throw (BusinessException) cause;
            }
            log.error(cause.getMessage(), cause);
            throw new BusinessException(CodeEnum.METHOD_INVOCATION_CREATE_COMMAND_FAILED);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(CodeEnum.METHOD_INVOCATION_CREATE_COMMAND_FAILED);
        }
    }

    /**
     * 根据app模块id获取参数封装方法
     * @param appModuleId app模块id
     * @return
     */
    private String getMethodNameFromDb(String appModuleId) {
        return appModuleMapper.getMethodNameFromDB(appModuleId);
    }

    /**
     * 根据app模块id获取处理器
     * @param appModuleId app模块id
     * @return
     */
    private String getHandlerClassNameFromDb(String appModuleId) {
        return appModuleMapper.getHandlerClassNameFromDB(appModuleId);
    }

    // ~ Variable & Constant
    // ========================================================================================================


    // ~ Public method
    // ========================================================================================================


    // ~ Override method
    // ========================================================================================================


    // ~ Private method
    // ========================================================================================================

    /**
     * 获取abaqus结果对象
     * @param param 计算参数
     * @param computeVo 任务参数
     * @return
     */
    private AbaqusResultVo generateAbaqusResultVo(AbaqusComputeParam param, StartComputeVo computeVo) {
        AbaqusResultVo abaqusResultVo = new AbaqusResultVo();
        switch (computeVo.getAppModuleId()) {
            case "2":
                abaqusResultVo = generateAbaqusDispResultVo(param, computeVo.getAppModuleId());
                break;
            case "3":
                abaqusResultVo = generateAbaqusDispResultVo(param, computeVo.getAppModuleId());
                break;
            default:
                abaqusResultVo = generateAbaqusTempResultVo(param, computeVo.getAppModuleId());
                break;
        }
        return abaqusResultVo;
    }

    /**
     * 获取abaqus温度结果对象
     * @param param 计算参数
     * @param appModuleId 任务参数
     * @return
     */
    private AbaqusResultVo generateAbaqusTempResultVo(AbaqusComputeParam param, String appModuleId) {
        AbaqusResultVo resultVo = new AbaqusResultVo();
        resultVo.setType(appModuleMapper.getModuleName(appModuleId));

        String path = outputPath + "\\\\PNG\\\\" + param.getJobVo().getJobName() + ".txt";
        Map<String, TempResultVo> tempResultVoMap = new HashMap<>();
        //读取存储结果的文件内容
        try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
            String line;
            while ((line = reader.readLine()) != null) {
                String[] s = line.split(":");
                switch (s[1]) {
                    case "max_val":
                        TempResultVo vo = tempResultVoMap.getOrDefault(s[0], new TempResultVo());
                        vo.setName(s[0]);
                        vo.setMaxTemperature(s[2]);
                        tempResultVoMap.put(s[0], vo);
                        break;
                    case "min_val":
                        TempResultVo vo2 = tempResultVoMap.getOrDefault(s[0], new TempResultVo());
                        vo2.setName(s[0]);
                        vo2.setMinTemperature(s[2]);
                        tempResultVoMap.put(s[0], vo2);
                        break;
                }
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(CodeEnum.FILE_READ_FAILED);
        }
        List<TempResultVo> list = new ArrayList<>();
        tempResultVoMap.forEach((k, v) -> {
            list.add(v);
        });
        AbaqusTempVo tempVo = new AbaqusTempVo();
        tempVo.setName(param.getStpName());
        tempVo.setTemps(list);
        resultVo.setResultVo(tempVo);
        return resultVo;
    }

    /**
     * 获取abaqus位移结果对象
     * @param param 计算参数
     * @param appModuleId 任务参数
     * @return
     */
    private AbaqusResultVo generateAbaqusDispResultVo(AbaqusComputeParam param, String appModuleId) {
        AbaqusResultVo resultVo = new AbaqusResultVo();
        resultVo.setType(appModuleMapper.getModuleName(appModuleId));
        String path = outputPath + "\\\\PNG\\\\" + param.getJobVo().getJobName() + ".txt";
        String previous = "";
        List<DispResultVo> dispResultVos = new ArrayList<>();

        //读取存储结果的文件内容
        try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
            String line;
            while ((line = reader.readLine()) != null) {
                //读取每个部件的位移
                String[] s = line.split(":");
                DispResultVo dispResultVo = previous.equals(s[0]) ? dispResultVos.get(dispResultVos.size() - 1) : new DispResultVo();
                dispResultVo.setName(s[0]);
                dispResultVo.getList().add(new Displacement(s[1], s[2]));
                if (!previous.equals(s[0])) dispResultVos.add(dispResultVo);
                previous = s[0];
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(CodeEnum.FILE_READ_FAILED);
        }
        AbaqusDispVo dispVo = new AbaqusDispVo();
        dispVo.setName(param.getStpName());
        dispVo.setDisplacements(dispResultVos);
        resultVo.setResultVo(dispVo);
        return resultVo;
    }


    /**
     * 读取msg计算文件内容，如果出现错误行，则存储错误行信息
     * @param jobName 任务名称
     * @param builder 存储文件内容
     */
    private void supplyLog(String jobName, StringBuilder builder) {
        String msgPath = outputPath + "\\\\" + jobName + ".msg";
        if (FileUtil.exist(msgPath)) {
            try (BufferedReader reader = new BufferedReader(new FileReader(msgPath))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    if (line.contains("ERROR")) {
                        builder.append(line).append(PyUtils.WRAP);
                    }
                }
            } catch (IOException e) {
                log.error(e.getMessage(), e);
                throw new BusinessException(CodeEnum.FILE_READ_FAILED);
            }
        }
    }

    /**
     * 上传结果文件
     *
     * @param local
     * @return
     */
    private String uploadResultFile(String local) {
        Map<String, String> params = new HashMap<>(8);
        File file = new File(local);

        Map<String, String> urls = apiProperties.getUrls();
        String url = urls.get("upload-file");
        params.put("moduleName", apiProperties.getModuleName());
        params.put("accessKey", apiProperties.getAccessKey());
        params.put("secretKey", apiProperties.getSecretKey());

        try (Response response = OkHttpUtil.uploadFile(url, file, params);
             ResponseBody responseBody = response.body()) {
            AssertUtil.isNull(responseBody, CodeEnum.UPLOAD_EXCEPTION);
            String body = new String(responseBody.bytes());
            Result<UploadVo> result = JSONUtil.toBean(body, new TypeReference<Result<UploadVo>>() {
            }, false);
            AssertUtil.isFalse(CodeEnum.UPLOAD_EXCEPTION, result.getCode() == 200);
            UploadVo resultData = result.getData();
            return resultData.getUrl();
        } catch (Exception e) {
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * 将odb转换为vtu的指令写入数据库
     * @param builder 指令
     * @param abaqusParam 计算参数
     * @param startComputeVo 任务参数
     */
    private void writeVtu(StringBuilder builder, AbaqusComputeParam abaqusParam, StartComputeVo startComputeVo) {
        //--instance "BEAMQ-1" --step "Step-1:-1" "Step-2:-1"
        builder.append("--instance ");
        List<AbaqusPartVo> parts = abaqusParam.getParts();
        for (AbaqusPartVo part : parts) {
            builder.append("\"").append(part.getName()).append("\" ");
        }
        builder.append("--step \"Step-1:-1\"");
        if ("2".equals(startComputeVo.getAppModuleId()) || "3".equals(startComputeVo.getAppModuleId())) {
            builder.append(" \"Step-2:-1\" ");
        }
    }
    // ~ Autowired
    // ========================================================================================================


}
